# -*- coding: utf-8 -*-
# בש״ד
#
# Miramar CMS for Django - Part of the Cuba Libre Project
# Copyright (C) 2009, Joshua "jag" Ginsberg <jag@flowtheory.net>
# 
# Por mi amor, que inspira a mi cada respiración y que echa de Cuba
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext, Context
from django.http import HttpResponseRedirect, Http404
from django.core.urlresolvers import reverse
from django.core import exceptions
from django.contrib.auth.decorators import permission_required
from django.contrib.redirects.models import Redirect
from django.contrib.sites.models import Site
from django.utils.translation import ugettext as _
from django.utils.html import escape
from django.conf import settings as site_settings
from django.views.generic import list_detail, create_update
import diff_match_patch
from miramar import models as miramar
from miramar import forms
from miramar import settings

def page_detail(request, slug, version_tag=None, revision=None,
                template_name='miramar/page_detail.html'):
    # One must be a staff member to see unpublished content
    if (version_tag or revision) and not request.user.is_staff:
        raise Http404
    try:
        page_obj = miramar.Page.on_site.get(slug__iexact=slug)
    except miramar.Page.DoesNotExist:
        # if the page does not exist but the user has the ability to create it
        # then redirect to the create page
        if request.user.has_perm('miramar.add_page'):
            request.user.message_set.create(
                message=_(u'That page does not exist, but you can create it.'))
            try:
                r = Redirect.objects.get(
                    site=Site.objects.get_current(),
                    old_path=reverse('miramar_page_detail', 
                                     kwargs={'slug': slug}))
            except Redirect.DoesNotExist:
                pass
            else:
                request.user.message_set.create(
                        message=_((u'There is presently a redirect from '
                                   u'%(old)s to %(new)s. Creating a new page '
                                   u'will override that redirect.')) % \
                                   {'old': r.old_path,
                                    'new': r.new_path})
            return HttpResponseRedirect(reverse('miramar_page_create',
                                                args=[slug]))
        else:
            raise Http404
    if version_tag and revision:
        pageversion_obj = get_object_or_404(miramar.PageVersion,
                                            page=page_obj,
                                            version_tag=version_tag,
                                            revision=revision)
    elif version_tag:
        # get the most recent revision for this tag
        try:
            pageversion_obj = miramar.PageVersion.objects.filter(
                page=page_obj, version_tag=version_tag).order_by('-revision')[0]
        except IndexError:
            raise Http404
    elif page_obj.published_version:
        # absent the version_tag or revision id, get the published version
        pageversion_obj = page_obj.published_version
    else:
        if request.user.has_perm('miramar.change_page'):
            return HttpResponseRedirect(reverse('miramar_page_update',
                                                kwargs={'slug': slug}))
        else:
            raise Http404

    ctx = RequestContext(request, {'page': page_obj, 
                                   'pageversion': pageversion_obj})
    return render_to_response(template_name, context_instance=ctx)

@permission_required('miramar.add_page')
def page_create(request, slug, template_name='miramar/page_create.html'):
    try:
        page = miramar.Page.on_site.get(slug__iexact=slug)
    except miramar.Page.DoesNotExist:
        # that's good :)
        pass
    else:
        message = _((u'You may not create a page with a URL stub that '
                     u'already exists.'))
        request.user.message_set.create(message=message)
        return HttpResponseRedirect(
            reverse('miramar_page_detail',
                    kwargs={'slug': slug}))
    
    if request.method == 'POST':
        form_obj = forms.PageForm(slug.lower(), request.user, request.POST)
        if form_obj.is_valid():
            new_page = form_obj.save()
            # create a new version and redirect to edit it
            new_pageversion = miramar.PageVersion.objects.create(
                page=new_page,
                author=request.user,
                version_tag=settings.DEFAULT_VERSION_TAG,
                revision=1,
                body=new_page.markup_engine.boiler_plate_page(new_page.title),
                comment='New page created.')
            request.user.message_set.create(
                message=u'%s has been created.' % new_page.title)
            return HttpResponseRedirect(
                reverse('miramar_pageversion_update',
                        kwargs={'slug': new_page.slug.lower(),
                                'version_tag': settings.DEFAULT_VERSION_TAG}))
    else:
        form_obj = forms.PageForm(slug.lower(), request.user)
    
    ctx = RequestContext(request, {'form': form_obj,
                                   'slug': slug.lower()})
    return render_to_response(template_name,
                              context_instance=ctx)

@permission_required('miramar.can_branch_pageversion')
def pageversion_branch(request, slug, version_tag, revision,
                       template_name='miramar/pageversion_branch.html'):
    page_obj = get_object_or_404(miramar.Page, slug__iexact=slug)
    try:
        pageversion_obj = miramar.PageVersion.objects.get(
            page=page_obj, version_tag=version_tag, revision=revision)
    except miramar.PageVersion.DoesNotExist:
        raise Http404
    if request.method == 'POST':
        form_obj = forms.PageVersionTagForm(page_obj, request.POST)
        if form_obj.is_valid():
            new_pageversion_obj = pageversion_obj.branch(
                request.user, form_obj.cleaned_data['version_tag'])
            request.user.message_set.create(
                message=_(u'%s version tag has been created.') % \
                new_pageversion_obj.version_tag)
            if request.GET.get('popup', False):
                ctx = Context({'MEDIA_URL': site_settings.MEDIA_URL})
                return render_to_response('miramar/popup_close.html',
                                          context_instance=ctx)
            else:
                return HttpResponseRedirect(
                    reverse('miramar_pageversion_update',
                            kwargs={'slug': slug,
                                    'version_tag': new_pageversion_obj.version_tag}))
    else:
        form_obj = forms.PageVersionTagForm(page_obj)
    ctx = RequestContext(request, {'form': form_obj,
                                   'page': page_obj,
                                   'pageversion': pageversion_obj})
    return render_to_response(template_name,
                              context_instance=ctx)
    
@permission_required('miramar.change_page')
def page_update(request, slug, template_name='miramar/page_update.html'):
    page_obj = get_object_or_404(miramar.Page, slug__iexact=slug)
    if request.method == 'POST':
        form_obj = forms.PageForm(slug, request.user, request.POST, 
                                  instance=page_obj)
        if form_obj.is_valid():
            form_obj.save()
            request.user.message_set.create(
                message=_(u'Your changes have been saved.'))
            return HttpResponseRedirect(
                reverse('miramar_page_update',
                        kwargs={'slug': slug}))
    else:
        form_obj = forms.PageForm(slug, request.user, instance=page_obj)
    ctx = RequestContext(request, {'form': form_obj,
                                   'page': page_obj})
    return render_to_response(template_name,
                              context_instance=ctx)

@permission_required('miramar.change_page')
def page_rename(request, slug, template_name='miramar/page_rename.html'):
    page_obj = get_object_or_404(miramar.Page, slug__iexact=slug)
    if request.method == 'POST':
        form_obj = forms.PageSlugChangeForm(slug, request.POST)
        if form_obj.is_valid():
            new_slug = form_obj.cleaned_data['new_slug']
            create_redirect = form_obj.cleaned_data['create_redirect']
            page_obj.rename(request.user, new_slug, create_redirect)
            if create_redirect:
                request.user.message_set.create(
                    message=_((u'The page has been renamed. Requests for '
                               u'%(old_slug)s will redirect to '
                               u'%(new_slug)s.')) % {'old_slug': slug,
                                                     'new_slug': new_slug})
            else:
                request.user.message_set.create(
                    message=_(u'The page has been renamed.'))
            return HttpResponseRedirect(
                reverse('miramar_page_update', kwargs={'slug': new_slug}))
    else:
        form_obj = forms.PageSlugChangeForm(slug)
    ctx = RequestContext(request, {'form': form_obj,
                                   'page': page_obj})
    return render_to_response(template_name,
                              context_instance=ctx)

@permission_required('miramar.can_revise_pageversion')
def pageversion_update(request, slug, version_tag, 
                       template_name='miramar/pageversion_update.html'):
    page_obj = get_object_or_404(miramar.Page, slug__iexact=slug)
    try:
        pageversion_obj = page_obj.pageversion_set.filter(
            version_tag=version_tag).order_by('-revision')[0]
    except IndexError:
        raise Http404
    if request.method == 'POST':
        form_obj = forms.PageVersionUpdateForm(
            request.POST,
            initial={'comment': u''},
                     instance=pageversion_obj)
        if form_obj.is_valid():
            pageversion_obj.revise(
                request.user,
                form_obj.cleaned_data['body'],
                form_obj.cleaned_data['comment'])
            request.user.message_set.create(
                message=_(u'Revision successful.'))
            return HttpResponseRedirect(reverse('miramar_page_update',
                                                kwargs={'slug': page_obj.slug}))
    else:
        form_obj = forms.PageVersionUpdateForm(initial={'comment': u''},
                                               instance=pageversion_obj)
    ctx = RequestContext(request, {'form': form_obj,
                                   'page': page_obj,
                                   'pageversion': pageversion_obj})
    return render_to_response(template_name,
                              context_instance=ctx)

@permission_required('miramar.change_page')
def pageversion_diff_form(request, slug, version_tag_a, revision_a,
                          template_name='miramar/pageversion_diff_form.html'):
    page_obj = get_object_or_404(miramar.Page, slug__iexact=slug)
    version_a = get_object_or_404(miramar.PageVersion, page=page_obj,
                                  version_tag=version_tag_a,
                                  revision=revision_a)
    choices = map(
        lambda pv: (u'%s/%s/' % (pv.version_tag,
                                 pv.revision),
                    u'%s:rev%d' % (pv.version_tag,
                                   pv.revision)),
        miramar.PageVersion.objects.filter(page=page_obj).exclude(id=version_a.id))
    ctx = RequestContext(request, {'page': page_obj,
                                   'pageversion': version_a,
                                   'choices': choices,
                                   'jquery_urlstub': settings.JQUERY_URLSTUB})
    return render_to_response(template_name, context_instance=ctx)
    
@permission_required('miramar.change_page')
def pageversion_diff(request, slug, version_tag_a, revision_a,
                     version_tag_b, revision_b,
                     template_name='miramar/pageversion_diff.html'):
    page_obj = get_object_or_404(miramar.Page, slug__iexact=slug)
    version_a = get_object_or_404(miramar.PageVersion, page=page_obj,
                                  version_tag=version_tag_a, 
                                  revision=revision_a)
    version_b = get_object_or_404(miramar.PageVersion, page=page_obj,
                                  version_tag=version_tag_b,
                                  revision=revision_b)
    dmp = diff_match_patch.diff_match_patch()
    diff = dmp.diff_main(version_a.body, version_b.body)
    dmp.diff_cleanupSemantic(diff)
    changes = u''
    for mode, snippet in diff:
        if mode == dmp.DIFF_EQUAL:
            changes += escape(snippet)
        elif mode == dmp.DIFF_DELETE:
            changes += u'<span class="delete">'+escape(snippet)+u'</span>'
        elif mode == dmp.DIFF_INSERT:
            changes += u'<span class="add">'+escape(snippet)+u'</span>'
    ctx = RequestContext(request, {'page': page_obj,
                                   'pageversion_a': version_a,
                                   'pageversion_b': version_b,
                                   'changes': changes,
                                   'jquery_urlstub': settings.JQUERY_URLSTUB})
    return render_to_response(template_name, context_instance=ctx)

    
@permission_required('miramar.can_publish_pageversion')
def pageversion_publish(request, slug, version_tag, revision,
                        template_name='miramar/pageversion_publish.html'):
    page_obj = get_object_or_404(miramar.Page, slug__iexact=slug)
    try:
        pageversion_obj = page_obj.pageversion_set.get(version_tag=version_tag,
                                                       revision=revision,
                                                       approved=True)
    except miramar.PageVersion.DoesNotExist:
        request.user.message_set.create(
            message=_(u'Invalid page version specified.'))
    else:
        if request.method == 'POST':
            try:
                pageversion_obj.publish(request.user)
            except exceptions.PermissionDenied, e:
                request.user.message_set.create(message=e.message)
            else:
                request.user.message_set.create(
                    message=_(u'Version successfully published.'))
        else:
            ctx = RequestContext(request, {'page': page_obj,
                                           'pageversion': pageversion_obj,
                                           'jquery_urlstub': settings.JQUERY_URLSTUB})
            return render_to_response(template_name, context_instance=ctx)
    if request.GET.get('popup', False):
        ctx = Context({'MEDIA_URL': site_settings.MEDIA_URL})
        return render_to_response('miramar/popup_close.html',
                                  context_instance=ctx)
    else:
        return HttpResponseRedirect(
            reverse('miramar_page_update', kwargs={'slug': slug}))

@permission_required('miramar.can_approve_pageversion')
def pageversion_approve(request, slug, version_tag, revision,
                        template_name='miramar/pageversion_approve.html'):
    page_obj = get_object_or_404(miramar.Page, slug__iexact=slug)
    try:
        pageversion_obj = page_obj.pageversion_set.get(version_tag=version_tag,
                                                         revision=revision)
    except miramar.PageVersion.DoesNotExist:
        request.user.message_set.create(
            message=_(u'Invalid page version specified.'))
    else:
        if request.method == 'POST':
            try:
                pageversion_obj.approve(request.user)
            except exceptions.PermissionDenied, e:
                request.user.message_set.create(message=e.message)
            else:
                request.user.message_set.create(
                    message=_(u'Version successfully approved for publishing.'))
        else:
            ctx = RequestContext(request, {'page': page_obj,
                                           'pageversion': pageversion_obj,
                                           'jquery_urlstub': settings.JQUERY_URLSTUB})
            return render_to_response(template_name, context_instance=ctx)
    if request.GET.get('popup', False):
        ctx = Context({'MEDIA_URL': site_settings.MEDIA_URL})
        return render_to_response('miramar/popup_close.html',
                                  context_instance=ctx)
    else:
        return HttpResponseRedirect(
            reverse('miramar_page_update', kwargs={'slug': slug}))

### IMAGE LIBRARY ###

@permission_required('miramar.can_view_imagelibrary')
def storedimage_list(request, template_name='miramar/storedimage_list.html'):
    return list_detail.object_list(request,
                                   queryset=miramar.StoredImage.objects.all(),
                                   paginate_by=25,
                                   template_name=template_name,
                                   allow_empty=True,
                                   template_object_name='storedimage',
                                   extra_context={
                                       'jquery_urlstub': settings.JQUERY_URLSTUB,
                                       'preview_js_urlstub': settings.PREVIEW_JS_URLSTUB})

@permission_required('miramar.add_storedimage')
def storedimage_create(request, template_name='miramar/storedimage_create.html'):
    return create_update.create_object(request,
                                       model=miramar.StoredImage,
                                       post_save_redirect=reverse(
                                           'miramar_storedimage_list'),
                                       template_name=template_name)

@permission_required('miramar.change_storedimage')
def storedimage_update(request, slug, 
                       template_name='miramar/storedimage_update.html'):
    return create_update.update_object(request,
                                       form_class=forms.StoredImageUpdateForm,
                                       slug=slug,
                                       slug_field='slug',
                                       post_save_redirect=reverse(
                                           'miramar_storedimage_list'),
                                       template_name=template_name,
                                       template_object_name='storedimage')

@permission_required('miramar.delete_storedimage')
def storedimage_delete(request, slug, 
                       template_name='miramar/storedimage_delete.html'):
    return create_update.delete_object(request,
                                       model=miramar.StoredImage,
                                       slug=slug,
                                       slug_field='slug',
                                       post_delete_redirect=reverse(
                                           'miramar_storedimage_list'),
                                       template_name=template_name,
                                       template_object_name='storedimage')

### FILE LIBRARY ###

@permission_required('miramar.can_view_filelibrary')
def storedfile_list(request, template_name='miramar/storedfile_list.html'):
    return list_detail.object_list(request,
                                   queryset=miramar.StoredFile.objects.all(),
                                   paginate_by=25,
                                   template_name=template_name,
                                   allow_empty=True,
                                   template_object_name='storedfile')

@permission_required('miramar.add_storedfile')
def storedfile_create(request, template_name='miramar/storedfile_create.html'):
    return create_update.create_object(request,
                                       model=miramar.StoredFile,
                                       post_save_redirect=reverse(
                                           'miramar_storedfile_list'),
                                       template_name=template_name)

@permission_required('miramar.change_storedfile')
def storedfile_update(request, slug, 
                       template_name='miramar/storedfile_update.html'):
    return create_update.update_object(request,
                                       form_class=forms.StoredFileUpdateForm,
                                       slug=slug,
                                       slug_field='slug',
                                       post_save_redirect=reverse(
                                           'miramar_storedfile_list'),
                                       template_name=template_name,
                                       template_object_name='storedfile')

@permission_required('miramar.delete_storedfile')
def storedfile_delete(request, slug, 
                       template_name='miramar/storedfile_delete.html'):
    return create_update.delete_object(request,
                                       model=miramar.StoredFile,
                                       slug=slug,
                                       slug_field='slug',
                                       post_delete_redirect=reverse(
                                           'miramar_storedfile_list'),
                                       template_name=template_name,
                                       template_object_name='storedfile')

    
